home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Mail / pine3.92 / pico / pico.c < prev    next >
C/C++ Source or Header  |  1996-03-14  |  34KB  |  1,483 lines

  1. #if    !defined(lint) && !defined(DOS)
  2. static char rcsid[] = "$Id: pico.c,v 4.92 1996/03/15 07:41:11 hubert Exp $";
  3. #endif
  4. /*
  5.  * Program:    Main Pine Composer routines
  6.  *
  7.  *
  8.  * Michael Seibel
  9.  * Networks and Distributed Computing
  10.  * Computing and Communications
  11.  * University of Washington
  12.  * Administration Builiding, AG-44
  13.  * Seattle, Washington, 98195, USA
  14.  * Internet: mikes@cac.washington.edu
  15.  *
  16.  * Please address all bugs and comments to "pine-bugs@cac.washington.edu"
  17.  *
  18.  *
  19.  * Pine and Pico are registered trademarks of the University of Washington.
  20.  * No commercial use of these trademarks may be made without prior written
  21.  * permission of the University of Washington.
  22.  * 
  23.  * Pine, Pico, and Pilot software and its included text are Copyright
  24.  * 1989-1996 by the University of Washington.
  25.  * 
  26.  * The full text of our legal notices is contained in the file called
  27.  * CPYRIGHT, included with this distribution.
  28.  *
  29.  *
  30.  * WEEMACS/PICO NOTES:
  31.  *
  32.  * 01 Nov 89 - MicroEmacs 3.6 vastly pared down and becomes a function call 
  33.  *            weemacs() and plugged into the Pine mailer.  Lots of unused
  34.  *           MicroEmacs code laying around.
  35.  *
  36.  * 17 Jan 90 - weemacs() became weemacs() the composer.  Header editing
  37.  *           functions added.
  38.  *
  39.  * 09 Sep 91 - weemacs() renamed pico() for the PIne COmposer.
  40.  *
  41.  */
  42.  
  43.  
  44. /*
  45.  * This program is in public domain; written by Dave G. Conroy.
  46.  * This file contains the main driving routine, and some keyboard processing
  47.  * code, for the MicroEMACS screen editor.
  48.  *
  49.  * REVISION HISTORY:
  50.  *
  51.  * 1.0  Steve Wilhite, 30-Nov-85
  52.  *      - Removed the old LK201 and VT100 logic. Added code to support the
  53.  *        DEC Rainbow keyboard (which is a LK201 layout) using the the Level
  54.  *        1 Console In ROM INT. See "rainbow.h" for the function key defs
  55.  *      Steve Wilhite, 1-Dec-85
  56.  *      - massive cleanup on code in display.c and search.c
  57.  *
  58.  * 2.0  George Jones, 12-Dec-85
  59.  *      - Ported to Amiga.
  60.  *
  61.  * 3.0  Daniel Lawrence, 29-Dec-85
  62.  *    16-apr-86
  63.  *    - updated documentation and froze development for 3.6 net release
  64.  */
  65.  
  66. #include        <stdio.h>
  67. #include    <setjmp.h>
  68. #include    <time.h>
  69.  
  70. /* make global definitions not external */
  71. #define    maindef
  72.  
  73. #include    "osdep.h"    /* operating system dependent includes */
  74. #include    "pico.h"    /* PIne COmposer definitions */
  75. #include        "estruct.h"    /* global structures and defines */
  76. #include    "efunc.h"    /* function declarations and name table    */
  77. #include    "edef.h"    /* global definitions */
  78. #include    "ebind.h"    /* default key bindings */
  79.  
  80.  
  81. #ifdef    ANSI
  82.     int  func_init(void);
  83.     void breplace(void *);
  84.     int  any_header_changes(void);
  85. #ifdef    _WINDOWS
  86.     int    composer_file_drop(int, int, char *);
  87. #endif
  88. #else
  89.     int  func_init();
  90.     void breplace();
  91.     int  any_header_changes();
  92. #endif
  93.  
  94.  
  95. /*
  96.  * function key mappings
  97.  */
  98. static int pfkm[12][2] = {
  99.     { F1,  (CTRL|'G')},
  100.     { F2,  (CTRL|'C')},
  101.     { F3,  (CTRL|'X')},
  102.     { F4,  (CTRL|'J')},
  103.     { F5,  (CTRL|'R')},
  104.     { F6,  (CTRL|'W')},
  105.     { F7,  (CTRL|'Y')},
  106.     { F8,  (CTRL|'V')},
  107.     { F9,  (CTRL|'K')},
  108.     { F10, (CTRL|'U')},
  109.     { F11, (CTRL|'O')},
  110. #ifdef    SPELLER
  111.     { F12, (CTRL|'T')}
  112. #else
  113.     { F12, (CTRL|'D')}
  114. #endif
  115. };
  116.  
  117.  
  118. /*
  119.  * flag for the various functions in pico() to set when ready
  120.  * for pico() to return...
  121.  */
  122. int      pico_all_done = 0;
  123. jmp_buf  finstate;
  124. char    *pico_anchor = NULL;
  125. extern struct headerentry *headents;
  126.  
  127. /*
  128.  * pico - the main routine for Pine's composer.
  129.  *
  130.  */
  131. pico(pm)
  132. PICO *pm;
  133. {
  134.     register int    c;
  135.     register int    f;
  136.     register int    n;
  137.     char     bname[NBUFN];        /* buffer name of file to read */
  138.     extern   struct on_display ods;
  139.     int      checkpointcnt = 0;
  140.     char     chkptfile[NLINE];
  141.  
  142.     Pmaster       = pm;
  143.     gmode      = MDWRAP;
  144.     gmode        |= pm->pine_flags;    /* high 4 bits rsv'd for pine */
  145.  
  146.     alt_speller   = pm->alt_spell;
  147.     pico_all_done = 0;
  148.     km_popped     = 0;
  149.  
  150.     if(!vtinit())            /* Init Displays.      */
  151.       return(COMP_CANCEL);
  152.  
  153.     strcpy(bname, "main");        /* default buffer name */
  154.     edinit(bname);            /* Buffers, windows.   */
  155.  
  156.     if(InitMailHeader(pm))        /* init mail header structure */
  157.       gmode &= ~(P_BODY | P_HEADEND);    /* flip off special header stuff */
  158.  
  159.     /* setup to process commands */
  160.     lastflag = 0;            /* Fake last flags.     */
  161.     curbp->b_mode |= gmode;        /* and set default modes*/
  162.  
  163.     pico_anchor = (char *)malloc((strlen(Pmaster->pine_anchor) + 1)
  164.                  * sizeof(char));
  165.     if(pico_anchor)
  166.       strcpy(pico_anchor, Pmaster->pine_anchor);
  167.  
  168.     bindtokey(0x7f, (gmode & P_DELRUBS) ? forwdel : backdel);
  169.  
  170.     if(pm->msgtext)
  171.       breplace(pm->msgtext);
  172.  
  173. #ifdef    _WINDOWS
  174.     mswin_allowpaste(MSWIN_PASTE_FULL);
  175.     mswin_setscrollcallback (pico_scroll_callback);
  176. #endif
  177.  
  178.     pico_all_done = setjmp(finstate);    /* jump out of HUP handler ? */
  179.  
  180.     if(gmode & MDALTNOW){
  181.     while(!pico_all_done){
  182.         if(((gmode & P_BODY) || !Pmaster->headents)
  183.            && alt_editor(0, 1) < 0)
  184.           break;            /* if problem, drop into pico */
  185.  
  186.         if(Pmaster->headents){
  187.         update();        /* paint screen, n' start editing... */
  188.         HeaderEditor((gmode & (P_HEADEND | P_BODY)) ? 2 : 0, 0);
  189.         gmode |= P_BODY;    /* make sure we enter alt ed next */
  190.         }
  191.         else
  192.           pico_all_done = COMP_EXIT;
  193.     }
  194.     }
  195.     else if(!pico_all_done){
  196.     if(gmode & P_BODY){        /* begin editing the header? */
  197.         ArrangeHeader();        /* line up pointers */
  198.     }
  199.     else{
  200.         update();            /* paint screen, */
  201.         HeaderEditor((gmode & P_HEADEND) ? 2 : 0, 0);
  202.     }
  203.  
  204.     /* prepare for checkpointing */
  205.     chkptfile[0] = '\0';
  206.     chkptinit((*Pmaster->ckptdir)(chkptfile, NLINE), NLINE);
  207.     }
  208.  
  209.     while(1){
  210.     if(pico_all_done){
  211. #ifdef    _WINDOWS
  212.         mswin_allowpaste(MSWIN_PASTE_DISABLE);
  213.         mswin_setscrollcallback (NULL);
  214. #endif
  215.         c = anycb() ? BUF_CHANGED : 0;
  216.         switch(pico_all_done){    /* prepare for/handle final events */
  217.           case COMP_EXIT :        /* already confirmed */
  218.         packheader();
  219.         c |= COMP_EXIT;
  220.         break;
  221.  
  222.           case COMP_CANCEL :    /* also already confirmed */
  223.         packheader();
  224.         c = COMP_CANCEL;
  225.         break;
  226.  
  227.           case COMP_GOTHUP:
  228.         /* 
  229.          * pack up and let caller know that we've received a SIGHUP
  230.          */
  231.         if(ComposerEditing)        /* expand addr if needed */
  232.           call_builder(&headents[ods.cur_e]);
  233.  
  234.         packheader();
  235.         c |= COMP_GOTHUP;
  236.         break;
  237.  
  238.           case COMP_SUSPEND :
  239.           default:            /* safest if internal error */
  240.         packheader();
  241.         c |= COMP_SUSPEND;
  242.         break;
  243.         }
  244.  
  245.         free(pico_anchor);
  246.         vttidy();            /* clean up tty modes */
  247.         zotdisplay();        /* blast display buffers */
  248.         zotedit();
  249.         unlink(chkptfile);
  250.         Pmaster = NULL;        /* blat global */
  251.  
  252.         return(c);
  253.     }
  254.  
  255.     if(km_popped){
  256.         km_popped--;
  257.         if(km_popped == 0) /* cause bottom three lines to be repainted */
  258.           curwp->w_flag |= WFHARD;
  259.     }
  260.  
  261.     if(km_popped){  /* temporarily change to cause menu to be painted */
  262.         term.t_mrow = 2;
  263.         curwp->w_ntrows -= 2;
  264.         curwp->w_flag |= WFMODE;
  265.         movecursor(term.t_nrow-2, 0); /* clear status line, too */
  266.         peeol();
  267.     }
  268.  
  269.     update();            /* Fix up the screen    */
  270.     if(km_popped){
  271.         term.t_mrow = 0;
  272.         curwp->w_ntrows += 2;
  273.     }
  274.  
  275. #ifdef    MOUSE
  276. #ifdef  EX_MOUSE
  277.     /* New mouse function for real mouse text seletion. */
  278.     register_mfunc(mouse_in_pico, 2, 0, term.t_nrow - (term.t_mrow+1),
  279.                term.t_ncol);
  280. #else
  281.     mouse_in_content(K_MOUSE, -1, -1, -1, 0);
  282.     register_mfunc(mouse_in_content, 2, 0, term.t_nrow - (term.t_mrow + 1),
  283.                term.t_ncol);
  284. #endif
  285. #endif
  286. #ifdef    _WINDOWS
  287.     mswin_setdndcallback (composer_file_drop);
  288. #endif
  289.     c = GetKey();    
  290. #ifdef    MOUSE
  291. #ifdef  EX_MOUSE
  292.     clear_mfunc(mouse_in_pico);
  293. #else
  294.     clear_mfunc(mouse_in_content);
  295. #endif
  296. #endif
  297. #ifdef    _WINDOWS
  298.     mswin_cleardndcallback ();
  299. #endif
  300.     if(c == NODATA || time_to_check()){    /* new mail ? */
  301.         if((*Pmaster->newmail)(c == NODATA ? 0 : 2, 1) >= 0){
  302.         if(km_popped){
  303.             term.t_mrow = 2;
  304.             curwp->w_ntrows -= 2;
  305.             curwp->w_flag |= WFHARD;
  306.             km_popped = 0;
  307.         }
  308.  
  309.         clearcursor();
  310.         mlerase();
  311.         (*Pmaster->showmsg)(c);
  312.         mpresf = 1;
  313.         }
  314.  
  315.         clearcursor();
  316.         movecursor(0, 0);
  317.     }
  318.  
  319.     if(km_popped)
  320.       switch(c){
  321.         case NODATA:
  322.         case (CTRL|'L'):
  323.           km_popped++;
  324.           break;
  325.         
  326.         default:
  327.           mlerase();
  328.           break;
  329.       }
  330.  
  331.     if(c == NODATA)        /* no op, getkey timed out */
  332.       continue;
  333.  
  334.     if (mpresf != FALSE) {        /* message stay around only  */
  335.         if (mpresf++ > NMMESSDELAY)    /* so long! */
  336.           mlerase();
  337.     }
  338.  
  339.     f = FALSE;            /* vestigial */
  340.     n = 1;
  341.                     /* Do it.               */
  342.     execute(normalize_cmd(c, pfkm, 2), f, n);
  343.     if(++checkpointcnt >= CHKPTDELAY){
  344.         checkpointcnt = 0;
  345.         writeout(chkptfile);
  346.     }
  347.     }
  348. }
  349.  
  350. /*
  351.  * Initialize all of the buffers and windows. The buffer name is passed down
  352.  * as an argument, because the main routine may have been told to read in a
  353.  * file by default, and we want the buffer name to be right.
  354.  */
  355.  
  356. /*
  357.  * For the pine composer, we don't want to take over the whole screen
  358.  * for editing.  the first some odd lines are to be used for message 
  359.  * header information editing.
  360.  */
  361. edinit(bname)
  362. char    bname[];
  363. {
  364.     register BUFFER *bp;
  365.     register WINDOW *wp;
  366.  
  367.     if(Pmaster)
  368.       func_init();
  369.  
  370.     bp = bfind(bname, TRUE, BFWRAPOPEN);    /* First buffer         */
  371.     wp = (WINDOW *) malloc(sizeof(WINDOW)); /* First window         */
  372.  
  373.     if (bp==NULL || wp==NULL){
  374.     if(Pmaster)
  375.       return(0);
  376.     else
  377.       exit(1);
  378.     }
  379.  
  380.     curbp  = bp;                            /* Make this current    */
  381.     wheadp = wp;
  382.     curwp  = wp;
  383.     wp->w_wndp  = NULL;                     /* Initialize window    */
  384.     wp->w_bufp  = bp;
  385.     bp->b_nwnd  = 1;                        /* Displayed.           */
  386.     wp->w_linep = bp->b_linep;
  387.     wp->w_dotp  = bp->b_linep;
  388.     wp->w_doto  = 0;
  389.     wp->w_markp = NULL;
  390.     wp->w_marko = 0;
  391.     bp->b_linecnt = -1;
  392.  
  393.     if(Pmaster){
  394.     term.t_mrow = Pmaster->menu_rows;
  395.     wp->w_toprow = ComposerTopLine = COMPOSER_TOP_LINE;
  396.     wp->w_ntrows = term.t_nrow - COMPOSER_TOP_LINE - term.t_mrow;
  397.     fillcol = Pmaster->fillcolumn;
  398.     if(Pmaster->oper_dir)
  399.       strncpy(opertree, Pmaster->oper_dir, NLINE);
  400.     }
  401.     else{
  402.     if(sup_keyhelp)
  403.       term.t_mrow = 0;
  404.     else
  405.       term.t_mrow = 2;
  406.  
  407.         wp->w_toprow = 2;
  408.         wp->w_ntrows = term.t_nrow - 2 - term.t_mrow;
  409.     if(userfillcol > 0)            /* set fill column */
  410.       fillcol = userfillcol;
  411.     else
  412.       fillcol = term.t_ncol - 6;
  413.     }
  414.  
  415.     /*
  416.      * MDSCUR mode implies MDTREE mode with a opertree of home directory,
  417.      * unless opertree has been set differently.
  418.      */
  419.     if(gmode&MDSCUR && !*opertree)
  420.       strncpy(opertree, gethomedir(NULL), NLINE);
  421.  
  422.     if(*opertree){
  423.     fixpath(opertree, NLINE);
  424.     gmode |= MDTREE;
  425.     }
  426.  
  427.     wp->w_force = 0;
  428.     wp->w_flag  = WFMODE|WFHARD;            /* Full.                */
  429. }
  430.  
  431.  
  432. /*
  433.  * This is the general command execution routine. It handles the fake binding
  434.  * of all the keys to "self-insert". It also clears out the "thisflag" word,
  435.  * and arranges to move it to the "lastflag", so that the next command can
  436.  * look at it. Return the status of command.
  437.  */
  438. execute(c, f, n)
  439. int c, f, n;
  440. {
  441.     register KEYTAB *ktp;
  442.     register int    status;
  443.     register int    i;
  444.  
  445.     ktp = (Pmaster) ? &keytab[0] : &pkeytab[0];
  446.  
  447.     while (ktp->k_fp != NULL) {
  448.     if (ktp->k_code == c) {
  449.  
  450.         if(lastflag&CFFILL){
  451.         curwp->w_flag |= WFMODE;
  452.         if(Pmaster == NULL)
  453.           sgarbk = TRUE;
  454.         }
  455.  
  456.         thisflag = 0;
  457.         status   = (*ktp->k_fp)(f, n);
  458.         if((lastflag & CFFILL) && (thisflag ^ CFFILL))
  459.           fdelete();
  460.  
  461.         lastflag = thisflag;
  462.  
  463.         /*
  464.          * Reset flag saying wrap should open a new line whenever
  465.          * we execute a command (as opposed to just typing in text).
  466.          * However, if that command leaves us in the same line on the
  467.          * screen, then don't reset.
  468.          */
  469.         if(curwp->w_flag & (WFMOVE | WFHARD))
  470.           curbp->b_flag |= BFWRAPOPEN;    /* wrap should open new line */
  471.  
  472.         return (status);
  473.     }
  474.     ++ktp;
  475.     }
  476.  
  477.     if(lastflag & CFFILL)        /* blat unusable fill data */
  478.       fdelete();
  479.  
  480.     if (VALID_KEY(c)) {            /* Self inserting.      */
  481.  
  482.     if (n <= 0) {                   /* Fenceposts.          */
  483.         lastflag = 0;
  484.         return (n<0 ? FALSE : TRUE);
  485.     }
  486.     thisflag = 0;                   /* For the future.      */
  487.  
  488.     /* if we are in overwrite mode, not at eol,
  489.        and next char is not a tab or we are at a tab stop,
  490.        delete a char forword            */
  491.     if (curwp->w_bufp->b_mode & MDOVER &&
  492.         curwp->w_doto < curwp->w_dotp->l_used &&
  493.         (lgetc(curwp->w_dotp, curwp->w_doto).c != '\t' ||
  494.          (curwp->w_doto) % 8 == 7))
  495.       ldelete(1L, FALSE);
  496.  
  497.     /* do the appropriate insertion */
  498.     /* pico never does C mode, this is simple */
  499.     status = linsert(n, c);
  500.  
  501.     /*
  502.      * Check to make sure we didn't go off of the screen
  503.      * with that character.  Take into account tab expansion.
  504.      * If so wrap the line...
  505.      */
  506.     if(curwp->w_bufp->b_mode & MDWRAP){
  507.         register int j;
  508.         register int k;
  509.  
  510.         for(i = j = k = 0; j < llength(curwp->w_dotp); j++, k++)
  511.           if(isspace(lgetc(curwp->w_dotp, j).c)){
  512.           if(lgetc(curwp->w_dotp, j).c == TAB)
  513.             while(k+1 & 0x07)
  514.               k++;
  515.           }
  516.           else if(k >= fillcol){
  517.           wrapword();
  518.           break;
  519.           }
  520.     }
  521.  
  522.     lastflag = thisflag;
  523.     return (status);
  524.     }
  525.     
  526.     if(c&CTRL)
  527.       emlwrite("\007Unknown Command: ^%c", (void *)(c&0xff));
  528.     else
  529.       emlwrite("\007Unknown Command", NULL);
  530.  
  531.     lastflag = 0;                           /* Fake last flags.     */
  532.     return (FALSE);
  533. }
  534.  
  535.  
  536.  
  537. /*
  538.  * Fancy quit command, as implemented by Norm. If the any buffer has
  539.  * changed do a write on that buffer and exit emacs, otherwise simply exit.
  540.  */
  541. quickexit(f, n)
  542. int f, n;
  543. {
  544.     register BUFFER *bp;    /* scanning pointer to buffers */
  545.  
  546.     bp = bheadp;
  547.     while (bp != NULL) {
  548.     if ((bp->b_flag&BFCHG) != 0    /* Changed.             */
  549.         && (bp->b_flag&BFTEMP) == 0) {    /* Real.                */
  550.         curbp = bp;        /* make that buffer cur    */
  551.         filesave(f, n);
  552.     }
  553.     bp = bp->b_bufp;            /* on to the next buffer */
  554.     }
  555.     wquit(f, n);                             /* conditionally quit   */
  556. }
  557.  
  558.  
  559.  
  560. /* 
  561.  * abort_composer - ask the question here, then go quit or 
  562.  *                  return FALSE
  563.  */
  564. abort_composer(f, n)
  565. int f, n;
  566. {
  567.     char *result;
  568.  
  569.     result = "";
  570.  
  571.     if(Pmaster->canceltest){
  572.         if(((Pmaster->pine_flags & P_ABOOK && !any_header_changes())
  573.          || (!(Pmaster->pine_flags & P_ABOOK) && !anycb()))
  574.       || (result = (*Pmaster->canceltest)())){
  575.         pico_all_done = COMP_CANCEL;
  576.         emlwrite(result, NULL);
  577.         return(TRUE);
  578.     }
  579.     else{
  580.         emlwrite("Cancel Cancelled", NULL);
  581.         curwp->w_flag |= WFMODE;        /* and modeline so we  */
  582.         sgarbk = TRUE;            /* redraw the keymenu  */
  583.         pclear(term.t_nrow - 1, term.t_nrow + 1);
  584.         return(FALSE);
  585.     }
  586.     }
  587.     else switch(mlyesno(Pmaster->headents
  588.      ? "Cancel message (answering \"Yes\" will abandon your mail message)"
  589.      : (anycb() == FALSE)
  590.          ? "Cancel Edit (and abandon changes)"
  591.          : "Cancel Edit",
  592.      FALSE)){
  593.       case TRUE:
  594.     pico_all_done = COMP_CANCEL;
  595.     return(TRUE);
  596.  
  597.       case ABORT:
  598.     emlwrite("\007Cancel Cancelled", NULL);
  599.     break;
  600.  
  601.       default:
  602.     mlerase();
  603.     }
  604.     return(FALSE);
  605. }
  606.  
  607.  
  608. /*
  609.  * suspend_composer - return to pine with what's been edited so far
  610.  */
  611. suspend_composer(f, n)
  612. int f, n;
  613. {
  614.     if(Pmaster && Pmaster->headents)
  615.       pico_all_done = COMP_SUSPEND;
  616.     else
  617.       (*term.t_beep)();
  618. }
  619.  
  620.  
  621.  
  622. /*
  623.  * Quit command. If an argument, always quit. Otherwise confirm if a buffer
  624.  * has been changed and not written out. Normally bound to "C-X C-C".
  625.  */
  626. wquit(f, n)
  627. int f, n;
  628. {
  629.     register int    s;
  630.  
  631.     if(Pmaster){
  632.     char *prompt, *result;
  633.  
  634.     /* First, make sure there are no outstanding problems */ 
  635.     if(AttachError()){
  636.         emlwrite("\007Problem with attachments!  Fix errors or delete attachments.", NULL);
  637.         return(FALSE);
  638.     }
  639.  
  640.     /*
  641.      * if we're not in header, show some of it as we verify sending...
  642.      */
  643.     display_for_send();
  644.     if((!(Pmaster->pine_flags & P_ABOOK) || any_header_changes())
  645.        && (result = (*Pmaster->exittest)())){
  646.         if(sgarbf)
  647.           update();
  648.  
  649.         lchange(WFHARD);            /* set update flags... */
  650.         curwp->w_flag |= WFMODE;        /* and modeline so we  */
  651.         sgarbk = TRUE;            /* redraw the keymenu  */
  652.         pclear(term.t_nrow - 2, term.t_nrow + 1);
  653.         emlwrite(result, NULL);
  654.     }
  655.     else{
  656.         pico_all_done = COMP_EXIT;
  657.         return(TRUE);
  658.     }
  659.     }
  660.     else{
  661.         if (f != FALSE                          /* Argument forces it.  */
  662.         || anycb() == FALSE                     /* All buffers clean.   */
  663.                         /* User says it's OK.   */
  664.         || (s=mlyesno("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES)", -1)) == FALSE) {
  665.                 vttidy();
  666.                 exit(0);
  667.         }
  668.  
  669.     if(s == TRUE){
  670.         if(filewrite(0,1) == TRUE)
  671.           wquit(1, 0);
  672.     }
  673.     else if(s == ABORT){
  674.         emlwrite("Exit cancelled", NULL);
  675.         if(term.t_mrow == 0)
  676.           curwp->w_flag |= WFHARD;    /* cause bottom 3 lines to paint */
  677.     }
  678.         return(s);
  679.     }
  680.  
  681.     return(FALSE);
  682. }
  683.  
  684.  
  685. /*
  686.  * Has any editing been done to headers?
  687.  */
  688. any_header_changes()
  689. {
  690.     struct headerentry *he;
  691.  
  692.     for(he = Pmaster->headents; he->name != NULL; he++)
  693.       if(he->dirty)
  694.     break;
  695.     
  696.     return(he->name && he->dirty);
  697. }
  698.  
  699.  
  700. /*
  701.  * Abort.
  702.  * Beep the beeper. Kill off any keyboard macro, etc., that is in progress.
  703.  * Sometimes called as a routine, to do general aborting of stuff.
  704.  */
  705. ctrlg(f, n)
  706. int f, n;
  707. {
  708.     emlwrite("Cancelled", NULL);
  709.     return (ABORT);
  710. }
  711.  
  712.  
  713. /* tell the user that this command is illegal while we are in
  714.  *  VIEW (read-only) mode
  715.  */
  716. rdonly()
  717. {
  718.     (*term.t_beep)();
  719.     emlwrite("Key illegal in VIEW mode", NULL);
  720.     return(FALSE);
  721. }
  722.  
  723.  
  724.  
  725. /*
  726.  * reset all globals to their initial values
  727.  */
  728. func_init()
  729. {
  730.     extern int    vtrow;
  731.     extern int    vtcol;
  732.     extern int    lbound;
  733.  
  734.     /*
  735.      * re-initialize global buffer type variables ....
  736.      */
  737.     fillcol = (term.t_ncol > 80) ? 77 : term.t_ncol - 6;
  738.     eolexist = TRUE;
  739.     revexist = FALSE;
  740.     sgarbf = TRUE;
  741.     mpresf = FALSE;
  742.     mline_open = FALSE;
  743.     ComposerEditing = FALSE;
  744.  
  745.     /*
  746.      * re-initialize hardware display variables ....
  747.      */
  748.     vtrow = vtcol = lbound = 0;
  749.     clearcursor();
  750.  
  751.     pat[0] = '\0';
  752. }
  753.  
  754.  
  755. /*
  756.  * pico_help - help function for standalone composer
  757.  */
  758. pico_help(text, title, i)
  759. char *text[], *title;
  760. int i;
  761. {
  762.     register    int numline = 0;
  763.     char        **p;
  764.  
  765.     p = text;
  766.     while(*p++ != NULL) 
  767.       numline++;
  768.     return(wscrollw(COMPOSER_TOP_LINE, term.t_nrow-1, text, numline));
  769. }
  770.  
  771.  
  772.  
  773. /*
  774.  * zotedit() - kills the buffer and frees all lines associated with it!!!
  775.  */
  776. zotedit()
  777. {
  778.     wheadp->w_linep = wheadp->w_dotp = wheadp->w_markp = NULL;
  779.     bheadp->b_linep = bheadp->b_dotp = bheadp->b_markp = NULL;
  780.  
  781.     free((char *) wheadp);            /* clean up window */
  782.     wheadp = NULL;
  783.     curwp  = NULL;
  784.  
  785.     free((char *) bheadp);            /* clean up buffers */
  786.     bheadp = NULL;
  787.     curbp  = NULL;
  788.  
  789.     zotheader();                /* blast header lines */
  790.  
  791.     kdelete();                    /* blast kill buffer */
  792.  
  793. }
  794.  
  795.  
  796. #ifdef    MOUSE
  797. /*
  798.  * Generic mouse handling functions
  799.  */
  800. MENUITEM  menuitems[12];        /* key labels and functions */
  801. MENUITEM *mfunc = NULL;            /* list of regional functions  */
  802. mousehandler_t    mtrack;            /* mouse tracking handler */
  803.  
  804. /* last mouse position */
  805. static  int levent = 0, lrow = 0, lcol = 0, doubleclick, lbutton, lflags;
  806. static  clock_t lastcalled = 0;
  807. static    mousehandler_t lastf;
  808.  
  809.  
  810. /*
  811.  * register_mfunc - register the given function to get called
  812.  *             on mouse events in the given display region
  813.  */
  814. register_mfunc(f, tlr, tlc, brr, brc)
  815. mousehandler_t    f;
  816. int        tlr, tlc, brr, brc;
  817. {
  818.     MENUITEM **mp;
  819.  
  820.     if(!mouseexist())
  821.       return(FALSE);
  822.  
  823.     for(mp = &mfunc; *mp; mp = &(*mp)->next)
  824.       ;
  825.  
  826.     *mp = (MENUITEM *)malloc(sizeof(MENUITEM));
  827.     memset(*mp, 0, sizeof(MENUITEM));
  828.  
  829.     (*mp)->action = f;
  830.     (*mp)->tl.r   = tlr;
  831.     (*mp)->br.r   = brr;
  832.     (*mp)->tl.c   = tlc;
  833.     (*mp)->br.c   = brc;
  834.     (*mp)->lbl.c  = (*mp)->lbl.r = 0;
  835.     (*mp)->label  = "";
  836.     return(TRUE);
  837. }
  838.  
  839.  
  840. /*
  841.  * clear_mfunc - clear any previously set mouse function
  842.  */
  843. void
  844. clear_mfunc(f)
  845. mousehandler_t f;
  846. {
  847.     MENUITEM *mp, *tp;
  848.  
  849.     if(mp = mfunc){
  850.     if(mp->action == f)
  851.       mfunc = mp->next;
  852.     else
  853.       for(tp = mp; tp->next; tp = tp->next)
  854.         if(tp->next->action == f){
  855.         mp = tp->next;
  856.         tp->next = tp->next->next;
  857.         break;
  858.         }
  859.  
  860.     if(mp){
  861.         mp->action = NULL;
  862.         free(mp);
  863.     }
  864.     }
  865. }
  866.  
  867.  
  868.  
  869. #ifdef EX_MOUSE
  870.  
  871. void
  872. clear_mtrack ()
  873. {
  874.     mtrack = NULL;
  875.     mswin_allowmousetrack (FALSE);
  876. }
  877.  
  878.  
  879. void
  880. register_mtrack (f)
  881. mousehandler_t    f;
  882. {
  883.     if (f) {
  884.     mtrack = f;
  885.     mswin_allowmousetrack (TRUE);
  886.     }
  887.     else
  888.     clear_mtrack ();
  889. }
  890.  
  891.  
  892. static void
  893. move_dot_to (row, col)
  894.     int row, col;
  895. {
  896.     LINE *lp;
  897.     int    i;
  898.     
  899.     lp = curwp->w_linep;
  900.     i = row - ((Pmaster) ? ComposerTopLine : 2);
  901.     while(i-- && lp != curbp->b_linep)    /* count from top */
  902.       lp = lforw(lp);
  903.     curgoal = col;
  904.     curwp->w_dotp = lp;            /* to new dot. */
  905.     curwp->w_doto = getgoal(lp);
  906.     curwp->w_flag |= WFMOVE;
  907. }
  908.  
  909.  
  910. /*
  911.  * mouse_in_pico
  912.  *
  913.  * When the mouse goes down in the body we set the mark and start 
  914.  * tracking.
  915.  *
  916.  * As the mouse moves we update the dot and redraw the screen.
  917.  *
  918.  * If the mouse moves above or below the pico body region of the 
  919.  * screen we scroll the text and update the dot position.
  920.  *
  921.  * When the mouse comes up we clean up.  If the mouse did not
  922.  * move, then we clear the mark and turn off the selection.
  923.  *
  924.  * Most of the mouse processing is handled here.  The exception is
  925.  * mouse down in the header.  Can't call HeaderEditor() from here so
  926.  * we send up the K_MOUSE character, which gets dispatched to
  927.  * mousepress(), which _can_ call HeaderEditor().
  928.  */
  929. unsigned long
  930. mouse_in_pico(mevent, row, col, button, flags)
  931.     int         mevent;
  932.     int      row, col, button, flags;
  933. {
  934.     unsigned long    rv = 0;        /* Our return value. */
  935.     int            trow, tcol;    /* translated row and col. */
  936.  
  937.     static int lheader = FALSE;        /* Mouse down was in header. */
  938.  
  939.   
  940.     /*
  941.      * What's up.
  942.      */
  943.     switch (mevent) {
  944.     case M_EVENT_DOWN:
  945.     /* Ignore mouse down if not in pico body region. */
  946.     if (row < 2 || row > term.t_nrow - (term.t_mrow+1)) {
  947.         clear_mtrack ();
  948.         break;
  949.         }
  950.     
  951.     /* Detect double clicks.  Not that we do anything with em, just
  952.      * detect them. */
  953. #ifdef    CLOCKS_PER_SEC
  954.     doubleclick = (lrow == row && lcol == col
  955.                && clock() < (lastcalled + CLOCKS_PER_SEC/2));
  956. #else
  957. #ifdef    CLK_TCK
  958. doubleclick = (lrow == row && lcol == col
  959.                && clock() < (lastcalled + CLK_TCK/2));
  960. #else
  961.     doubleclick = FALSE;
  962. #endif
  963. #endif
  964.     lastcalled  = clock();
  965.     lheader        = FALSE;    /* Rember mouse down position. */
  966.     levent        = mevent;
  967.     lrow        = row;
  968.     lcol        = col;
  969.     lbutton     = button;
  970.     lflags      = flags;
  971.     
  972.     /* Mouse down in body? */
  973.     if (row < (Pmaster ? ComposerTopLine : 2)) {
  974.         /* Mouse down in message header -> no tracking, just remember
  975.          * where */
  976.         lheader = TRUE;
  977.         }
  978.     else {
  979.         /* Mouse down in message.
  980.          * If no shift key and an existing mark -> clear the mark.
  981.          * If shift key and no existing mark -> set mark before moving */
  982.         if (!(flags & M_KEY_SHIFT) && curwp->w_markp) 
  983.         setmark (0,1);        /* this clears the mark. */
  984.         else if (flags & M_KEY_SHIFT && !curwp->w_markp)
  985.         setmark (0,1);        /* while this sets the mark. */
  986.         
  987.         /* Reposition dot to mouse down. */
  988.         move_dot_to (row, col);
  989.         
  990.         /* Set the mark to dot if no existing mark. */
  991.         if (curwp->w_markp == NULL) 
  992.         setmark (0,1);
  993.  
  994.         /* Track mouse movement. */
  995.         register_mtrack (mouse_in_pico);
  996.         update ();
  997.         lheader = FALSE;        /* Just to be sure. */
  998.         }
  999.     break;
  1000.     
  1001.     
  1002.     case M_EVENT_TRACK:
  1003.     /* Mouse tracking. */
  1004.     if (lheader)            /* Ignore mouse movement in header. */
  1005.         break;
  1006.     
  1007.     /* If above or below body, scroll body and adjust the row and col. */
  1008.     if (row < (Pmaster ? ComposerTopLine : 2)) {
  1009.         /* Scroll text down screen and move dot to top left corner. */
  1010.         scrollupline (0,1);
  1011.         trow = (Pmaster) ? ComposerTopLine : 2;
  1012.         tcol = 0;
  1013.         }
  1014.     else if (row > term.t_nrow - (term.t_mrow + 1)) {
  1015.         /* Scroll text up screen and move dot to bottom right corner. */
  1016.         scrolldownline (0,1);
  1017.         trow = term.t_nrow - (term.t_mrow + 1);
  1018.         tcol = term.t_ncol;
  1019.         }
  1020.     else {
  1021.         trow = row;
  1022.         tcol = col;
  1023.         }
  1024.  
  1025.     /* Move dot to target column. */
  1026.     move_dot_to (trow, tcol);
  1027.     
  1028.     /* Update screen. */
  1029.     update ();
  1030.     break;
  1031.  
  1032.     
  1033.     case M_EVENT_UP:
  1034.     if (lheader) {
  1035.         lheader = FALSE;
  1036.         /* Last down in header. */
  1037.         if (row == lrow && col == lcol) {
  1038.         /* Mouse up and down in same place in header.  Means the
  1039.          * user want to edit the header.  Return K_MOUSE which
  1040.          * will cause mousepress to be called, which will
  1041.          * call HeaderEditor.  Can't call HeaderEditor from here
  1042.          * because that would mess up layering. */
  1043.         if (curwp->w_marko)
  1044.             setmark (0,1);
  1045.         rv = ((unsigned long)K_MOUSE << 16) | TRUE;
  1046.         }
  1047.         }
  1048.     else {
  1049.         /* If up at same place, clear mark */
  1050.         if (curwp->w_markp == curwp->w_dotp && 
  1051.             curwp->w_marko == curwp->w_doto) {
  1052.         setmark (0,1);
  1053.         curwp->w_flag |= WFMOVE;
  1054.         }
  1055.         clear_mtrack ();
  1056.         update ();
  1057.         }
  1058.     break;    
  1059.     }
  1060.     
  1061.     return(rv);
  1062. }
  1063. #endif
  1064.  
  1065.  
  1066.  
  1067. /*
  1068.  * mouse_in_content - general mechanism used to pass recognized mouse
  1069.  *              events in predefined region back thru the usual
  1070.  *              keyboard input stream.  The actual return value
  1071.  *              passed back from this function is set dynamically
  1072.  *              via the "down" argument which is read when both the
  1073.  *              "row" and "col" arguments are negative.
  1074.  */
  1075. unsigned long
  1076. mouse_in_content(mevent, row, col, button, flags)
  1077.     int      mevent;
  1078.     int      row, col, button, flags;
  1079. {
  1080.     unsigned long   rv = 0;
  1081.     static unsigned mouse_val = K_MOUSE;
  1082.  
  1083.     if(row == -1 && col == -1){
  1084.     mouse_val = mevent;            /* setting return value */
  1085.     }
  1086.     else {
  1087.     /* A real event. */
  1088.     levent = mevent;
  1089.     switch (mevent) {
  1090.     case M_EVENT_DOWN:
  1091.         /* Mouse down does not mean anything, just keep track of 
  1092.          * where it went down and if this is a double click. */
  1093. #ifdef    CLOCKS_PER_SEC
  1094.         doubleclick = (lrow == row && lcol == col
  1095.                && clock() < (lastcalled + CLOCKS_PER_SEC/2));
  1096. #else
  1097. #ifdef    CLK_TCK
  1098.         doubleclick = (lrow == row && lcol == col
  1099.                && clock() < (lastcalled + CLK_TCK/2));
  1100. #else
  1101.         doubleclick = FALSE;
  1102. #endif
  1103. #endif
  1104.         lastcalled    = clock();
  1105.         lrow    = row;
  1106.         lcol    = col;
  1107.         lbutton    = button;
  1108.         lflags    = flags;
  1109.         break;
  1110.  
  1111.     case M_EVENT_UP:
  1112.         /* Mouse up.  If in the same position as it went down
  1113.          * then we return the value set above, which goes into
  1114.          * the character input stream, which gets processed as
  1115.          * a mouse event by some upper layer, which calls to 
  1116.          * mouse_get_last(). */
  1117.         if (lrow == row && lcol == col) {
  1118.         rv = mouse_val;
  1119.         rv = (rv << 16) | TRUE;
  1120.         }
  1121.         break;
  1122.         
  1123.     case M_EVENT_TRACK:
  1124.         break;
  1125.     }
  1126.     }
  1127.  
  1128.     return(rv);
  1129. }
  1130.  
  1131.  
  1132. /*
  1133.  * mouse_get_last - Get last mouse event.
  1134.  *
  1135.  */
  1136. void
  1137. mouse_get_last(f, mp)
  1138.     mousehandler_t *f;
  1139.     MOUSEPRESS *mp;
  1140. {
  1141.     if (f != NULL)
  1142.         *f  = lastf;
  1143.     if (mp != NULL) {
  1144.     mp->mevent    = levent;
  1145.     mp->row        = lrow;
  1146.     mp->col        = lcol;
  1147.     mp->doubleclick = doubleclick;
  1148.     mp->button    = lbutton;
  1149.     mp->flags    = lflags;
  1150.     }
  1151. }
  1152.  
  1153.  
  1154.  
  1155. /*
  1156.  * register_key - register the given keystroke to accept mouse events
  1157.  */
  1158. void
  1159. register_key(i, rval, label, label_printer, row, col, len)
  1160. int       i;
  1161. unsigned  rval;
  1162. char     *label;
  1163. void      (*label_printer)();
  1164. int       row, col, len;
  1165. {
  1166.     if(i > 11)
  1167.       return;
  1168.  
  1169.     menuitems[i].val   = rval;
  1170.     menuitems[i].tl.r  = menuitems[i].br.r = row;
  1171.     menuitems[i].tl.c  = col;
  1172.     menuitems[i].br.c  = col + len;
  1173.     menuitems[i].lbl.r = menuitems[i].tl.r;
  1174.     menuitems[i].lbl.c = menuitems[i].tl.c;
  1175.     menuitems[i].label_hiliter = label_printer;
  1176.     if(menuitems[i].label){
  1177.     free(menuitems[i].label);
  1178.     menuitems[i].label = NULL;
  1179.     }
  1180.  
  1181.     if(label
  1182.        && (menuitems[i].label =(char *)malloc((strlen(label)+1)*sizeof(char))))
  1183.       strcpy(menuitems[i].label, label);
  1184. }
  1185. #endif    /* MOUSE */
  1186.  
  1187.  
  1188. /* 
  1189.  * Below are functions for use outside pico to manipulate text
  1190.  * in a pico's native format (circular linked list of lines).
  1191.  *
  1192.  * The idea is to streamline pico use by making it fairly easy
  1193.  * for outside programs to prepare text intended for pico's use.
  1194.  * The simple char * alternative is messy as it requires two copies
  1195.  * of the same text, and isn't very economic in limited memory
  1196.  * situations (THANKS BELLEVUE-BILLY.).
  1197.  */
  1198. typedef struct picotext {
  1199.     LINE *linep;
  1200.     LINE *dotp;
  1201.     short doto;
  1202.     short crinread;
  1203. } PICOTEXT;
  1204.  
  1205. #define PT(X)    ((PICOTEXT *)(X))
  1206.  
  1207. /*
  1208.  * pico_get - return window struct pointer used as a handle
  1209.  *            to the other pico_xxx routines.
  1210.  */
  1211. void *
  1212. pico_get()
  1213. {
  1214.    PICOTEXT *wp = NULL;
  1215.    LINE     *lp = NULL;
  1216.  
  1217.    if(wp = (PICOTEXT *)malloc(sizeof(PICOTEXT))){
  1218.        wp->crinread = 0;
  1219.        if((lp = lalloc(0)) == NULL){
  1220.        free(wp);
  1221.        return(NULL);
  1222.        }
  1223.  
  1224.        wp->dotp = wp->linep = lp->l_fp = lp->l_bp = lp;
  1225.        wp->doto = 0;
  1226.    }
  1227.    else
  1228.      emlwrite("Can't allocate space for text", NULL);
  1229.  
  1230.    return((void *)wp);
  1231. }
  1232.  
  1233. /*
  1234.  * pico_give - free resources and give up picotext struct
  1235.  */
  1236. void
  1237. pico_give(w)
  1238. void *w;
  1239. {
  1240.     register LINE *lp;
  1241.     register LINE *fp;
  1242.  
  1243.     fp = lforw(PT(w)->linep);
  1244.     while((lp = fp) != PT(w)->linep){
  1245.         fp = lforw(lp);
  1246.     free(lp);
  1247.     }
  1248.     free(PT(w)->linep);
  1249.     free((PICOTEXT *)w);
  1250. }
  1251.  
  1252. /*
  1253.  * pico_readc - return char at current point.  Up to calling routines
  1254.  *              to keep cumulative count of chars.
  1255.  */
  1256. int
  1257. pico_readc(w, c)
  1258. void          *w;
  1259. unsigned char *c;
  1260. {
  1261.     int rv     = 0;
  1262.  
  1263.     if(PT(w)->crinread){
  1264.     *c = '\012';                /* return LF */
  1265.     PT(w)->crinread = 0;
  1266.     rv++;
  1267.     }
  1268.     else if(PT(w)->doto < llength(PT(w)->dotp)){ /* normal char to return */
  1269.         *c = (unsigned char) lgetc(PT(w)->dotp, (PT(w)->doto)++).c;
  1270.     rv++;
  1271.     }
  1272.     else if(PT(w)->dotp != PT(w)->linep){ /* return line break */
  1273.     PT(w)->dotp = lforw(PT(w)->dotp);
  1274.     PT(w)->doto = 0;
  1275. #if    defined(DOS) || defined(OS2)
  1276.     *c = '\015';
  1277.     PT(w)->crinread++;
  1278. #else
  1279.     *c = '\012';                /* return local eol! */
  1280. #endif
  1281.     rv++;
  1282.     }                        /* else no chars to return */
  1283.  
  1284.     return(rv);
  1285. }
  1286.  
  1287.  
  1288. /*
  1289.  * pico_writec - write a char into picotext and advance pointers.
  1290.  *               Up to calling routines to keep track of total chars
  1291.  *               written
  1292.  */
  1293. int
  1294. pico_writec(w, c)
  1295. void *w;
  1296. int   c;
  1297. {
  1298.     int   rv = 0;
  1299.  
  1300.     if(c == '\r')                /* ignore CR's */
  1301.       rv++;                    /* so fake it */
  1302.     else if(c == '\n'){                /* insert newlines on LF */
  1303.     /*
  1304.      * OK, if there are characters on the current line or 
  1305.      * dotp is pointing to the delimiter line, insert a newline
  1306.      * No here's the tricky bit; preserve the implicit EOF newline.
  1307.      */
  1308.     if(lforw(PT(w)->dotp) == PT(w)->linep && PT(w)->dotp != PT(w)->linep){
  1309.         PT(w)->dotp = PT(w)->linep;
  1310.         PT(w)->doto = 0;
  1311.     }
  1312.     else{
  1313.         register LINE *lp;
  1314.  
  1315.         if((lp = lalloc(0)) == NULL){
  1316.         emlwrite("Can't allocate space for more characters",NULL);
  1317.         return(0);
  1318.         }
  1319.  
  1320.         if(PT(w)->dotp == PT(w)->linep){
  1321.         lforw(lp) = PT(w)->linep;
  1322.         lback(lp) = lback(PT(w)->linep);
  1323.         lforw(lback(lp)) = lback(PT(w)->linep) = lp;
  1324.         }
  1325.         else{
  1326.         lforw(lp) = lforw(PT(w)->dotp);
  1327.         lback(lp) = PT(w)->dotp;
  1328.         lback(lforw(lp)) = lforw(PT(w)->dotp) = lp;
  1329.         PT(w)->dotp = lp;
  1330.         PT(w)->doto = 0;
  1331.         }
  1332.     }
  1333.  
  1334.     rv++;
  1335.     }
  1336.     else
  1337.       rv = geninsert(&PT(w)->dotp, &PT(w)->doto, PT(w)->linep, c, 0, 1, NULL);
  1338.  
  1339.     return((rv) ? 1 : 0);            /* return number written */
  1340. }
  1341.  
  1342.  
  1343. /*
  1344.  * pico_puts - just write the given string into the text
  1345.  */
  1346. int
  1347. pico_puts(w, s)
  1348. void *w;
  1349. char *s;
  1350. {
  1351.     while(*s != '\0')
  1352.       pico_writec(w, (int)*s++);
  1353. }
  1354.  
  1355.  
  1356. /*
  1357.  * pico_seek - position dotp and dot at requested location
  1358.  */
  1359. int
  1360. pico_seek(w, offset, orig)
  1361. void *w;
  1362. long  offset;
  1363. int   orig;
  1364. {
  1365.     register LINE *lp;
  1366.  
  1367.     PT(w)->crinread = 0;
  1368.     switch(orig){
  1369.       case 0 :                /* SEEK_SET */
  1370.     PT(w)->dotp = lforw(PT(w)->linep);
  1371.     PT(w)->doto = 0;
  1372.       case 1 :                /* SEEK_CUR */
  1373.     lp = PT(w)->dotp;
  1374.     while(lp != PT(w)->linep){
  1375.         if(offset <= llength(lp)){
  1376.         PT(w)->doto = (int)offset;
  1377.         PT(w)->dotp = lp;
  1378.         break;
  1379.         }
  1380.  
  1381.         offset -= ((long)llength(lp)
  1382. #if defined(DOS) || defined(OS2)
  1383.                + 2L);
  1384. #else
  1385.                + 1L);
  1386. #endif
  1387.         lp = lforw(lp);
  1388.     }
  1389.         break;
  1390.  
  1391.       case 2 :                /* SEEK_END */
  1392.     PT(w)->dotp = lback(PT(w)->linep);
  1393.     PT(w)->doto = llength(PT(w)->dotp);
  1394.     break;
  1395.       default :
  1396.         return(-1);
  1397.     }
  1398.  
  1399.     return(0);
  1400. }
  1401.  
  1402.  
  1403. /*
  1404.  * breplace - replace the current window's text with the given 
  1405.  *            LINEs
  1406.  */
  1407. void
  1408. breplace(w)
  1409. void *w;
  1410. {
  1411.     register LINE *lp;
  1412.     register LINE *fp;
  1413.  
  1414.     fp = lforw(curbp->b_linep);
  1415.     while((lp = fp) != curbp->b_linep){        /* blast old lines */
  1416.         fp = lforw(lp);
  1417.     free(lp);
  1418.     }
  1419.     free(curbp->b_linep);
  1420.  
  1421.     curbp->b_linep   = PT(w)->linep;            /* arrange pointers */
  1422.  
  1423.     curwp->w_linep   = lforw(curbp->b_linep);
  1424.     curwp->w_dotp    = lforw(curbp->b_linep);
  1425.     curwp->w_doto    = 0;
  1426.     curwp->w_markp   = curwp->w_imarkp = NULL;
  1427.     curwp->w_marko   = curwp->w_imarko = 0;
  1428.  
  1429.     curbp->b_dotp    = curwp->w_dotp;
  1430.     curbp->b_doto    = curbp->b_marko  = 0;
  1431.     curbp->b_markp   = NULL;
  1432.     curbp->b_linecnt = -1;
  1433.  
  1434.     curwp->w_flag |= WFHARD;
  1435. }
  1436.  
  1437.  
  1438. #ifdef    _WINDOWS
  1439. /*
  1440.  *
  1441.  */
  1442. int
  1443. composer_file_drop(x, y, filename)
  1444.     int   x, y;
  1445.     char *filename;
  1446. {
  1447.     int attached = 0;
  1448.     if((ComposerTopLine > 2 && x <= ComposerTopLine)
  1449.        || !LikelyASCII(filename)){
  1450.     AppendAttachment(filename, NULL, NULL);
  1451.     attached++;
  1452.     }
  1453.     else{
  1454.     setimark(FALSE, 1);
  1455.     ifile(filename);
  1456.     swapimark(FALSE, 1);
  1457.     }
  1458.  
  1459.     if(ComposerEditing){        /* update display */
  1460.     PaintBody(0);
  1461.     }
  1462.     else{
  1463.     refresh(0, 1);
  1464.     update();
  1465.     }
  1466.  
  1467.     if(attached)
  1468.       emlwrite("Attached dropped file \"%s\"", filename);
  1469.     else
  1470.       emlwrite("Inserted dropped file \"%s\"", filename);
  1471.  
  1472.     if(ComposerEditing){        /* restore cursor */
  1473.     HeaderPaintCursor();
  1474.     }
  1475.     else{
  1476.     curwp->w_flag |= WFHARD;
  1477.     update();
  1478.     }
  1479.  
  1480.     return(1);
  1481. }
  1482. #endif
  1483.